import { BigNumber, BigNumberish, ethers } from "ethers";
import { logger, sleep } from "../index";
import axios from "axios";

export enum GasPriceProviderType {
  OnChain,
  Fixed,
  DeBank // fast, normal, slow
}

export class GasPriceProvider {
  private type: GasPriceProviderType;
  private tempGasMultiplier: number = 0;

  constructor(public provider: ethers.providers.StaticJsonRpcProvider, public chain: string, public option: string) {
    if (option == "0") {
      this.type = GasPriceProviderType.OnChain;
    } else if (option == "fast" || option == "normal" || option == "slow") {
      this.type = GasPriceProviderType.DeBank;
    } else {
      this.type = GasPriceProviderType.Fixed;
    }
  }

  private async getGasPriceInternal(): Promise<BigNumberish> {
    switch (this.type) {
      case GasPriceProviderType.Fixed:
        return this.option;
      case GasPriceProviderType.DeBank:
        while (true) {
          try {
            const resp = await axios.get(`https://api.debank.com/chain/gas_price_dict_v2?chain=${this.chain}`);
            return resp.data.data[this.option].price;
          } catch (e) {
            await logger.error(`Get DeBank Gas Price fail for ${this.chain}, retrying`, e);
          }
          await sleep(1000);
        }
      case GasPriceProviderType.OnChain:
      default:
        while (true) {
          try {
            return this.provider.getGasPrice();
          } catch (e) {
            await logger.error(`Get On Chain Gas Price fail for ${this.chain}, retrying`, e);
          }
          await sleep(1000);
        }
    }
  }

  setNextGasMultiplier(m: number) {
    this.tempGasMultiplier = m;
  }

  async getGasPrice(): Promise<BigNumberish> {
    let gas = await this.getGasPriceInternal();
    if (this.tempGasMultiplier > 0) {
       gas = BigNumber.from(gas).mul(this.tempGasMultiplier).div(100);
       this.tempGasMultiplier = 0;
    }
    return gas;
  }
}
